#pragma once

#include <boost/asio.hpp>
//#include "../../static_pool/static_pool.h"
#include <array>
#include <vector>
#include <functional>
#include <memory>
#include "socket.hpp"
#include "../../parallel/thread.hpp"
#include "../../smart_ptr/smart_ptr.hpp"
#include "../../fast_buffer/fast_buffer.hpp"

namespace umtl
{
	//////////////////////////////////////////////////////////////////////////
	//

	typedef boost::asio::ip::tcp tcp;
	typedef boost::asio::ip::udp udp;

	//////////////////////////////////////////////////////////////////////////
	//

	template< typename protocol >
	class connection
	{
	public:
		typedef protocol protocol;
		typedef typename socket_type_selector< protocol >::type socket_type;
		typedef smart_ptr<connection> pointer;
		typedef std::tr1::function< void(connection* conn, char const * packet, size_t size) > read_handler_t;
		typedef std::tr1::function< void(connection* conn) > close_handler_t;
		static connection * create( read_handler_t & read_handler, close_handler_t & close_handler );

		socket_type & socket() { return socket_; }

		void listen( unsigned short int port );
		void connect( std::string const & host, std::string const & port );
		void read();
		void send( char const * data, size_t len/*, std::tr1::function< void(char const *) > release_data*/ );
		void run();

	private:
		void parse_packet();

		connection( read_handler_t & read_handler, close_handler_t & close_handler );

		boost::asio::io_service io_service_;
		socket_type socket_;

		size_t bytes_reserved_;
		size_t bytes_transferred_;

		typedef std::tr1::array< char, 256 > ReadBuffer;
		typedef fast_buffer_t< char > ReadPackets;
		ReadBuffer read_buffer_;
		ReadPackets read_packets_;
		
		boost::asio::detail::wrapped_handler< boost::asio::strand, read_handler_t > read_handler_;
		close_handler_t close_handler_;
	};

	//////////////////////////////////////////////////////////////////////////
	//

	template< typename protocol >
	struct connections
	{
		typedef protocol protocol;
		typedef connection< protocol > connection;
		typedef typename connection::pointer connection_ptr;
		typedef std::map< connection*, connection_ptr > type;

		connections( type & connections, parallel::critical_section & critical_section )
			: connections_(connections), critical_section_(critical_section), locker_( critical_section ) {}

		connections( connections & other )
			: connections_(other.connections_), critical_section_( other.critical_section_ ), locker_( critical_section_ ) {}

		type * operator->() { return &connections_; }
		type & operator*() { return connections_; }
		operator type() { return connections_; }

	private:
		type & connections_;
		parallel::critical_section & critical_section_;
		parallel::critical_section::section_locker locker_;
	};

	//////////////////////////////////////////////////////////////////////////
	//

	typedef connection< tcp > tcp_connection;
	typedef connection< udp > udp_connection;
	typedef connections< tcp > tcp_connections;
	typedef connections< udp > udp_connections;

	//////////////////////////////////////////////////////////////////////////
}

#include "connection.hpp"